﻿using DocumentFormat.OpenXml.Lite.Core.Office;
using DocumentFormat.OpenXml.Lite.SpreadsheetML.Excel.Base;
using DocumentFormat.OpenXml.Lite.SpreadsheetML.Excel.Types;
using DocumentFormat.OpenXml.Lite.SpreadsheetML.Excel.WorksheetElements;
using DocumentFormat.OpenXml.Lite.Xml;
using System;
using IO = System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Xml;
using DocumentFormat.OpenXml.Lite.Helper;
using DocumentFormat.OpenXml.Lite.Core.Interfaces;

namespace DocumentFormat.OpenXml.Lite.SpreadsheetML.Excel.Table
{
    [XmlRoot("table", Namespace = Constants.ExcelMain)]
    public class Table : XmlSerializable, IOfficeElement, ISerializable
    {
        [XmlIgnore]
        public Guid DocumentId { get; set; }

        [XmlIgnore]
        public string RelationshipId { get; set; }

        #region Attributes

        [XmlAttribute("id", Form = XmlSchemaForm.Qualified)]
        public uint Id { get; set; }

        [XmlAttribute("ref", Form = XmlSchemaForm.Qualified)]
        public string Reference { get; set; }

        [XmlAttribute("displayName", Form = XmlSchemaForm.Qualified)]
        public string DisplayName { get; set; }

        [Optional]
        [XmlAttribute("name", Form = XmlSchemaForm.Qualified)]
        public string Name { get; set; }

        [Optional]
        [XmlAttribute("comment", Form = XmlSchemaForm.Qualified)]
        public string Comment { get; set; }

        [Optional]
        [XmlAttribute("tableType", Form = XmlSchemaForm.Qualified)]
        public Nullable<ST_TableType> TableType { get; set; }

        [Optional]
        [XmlAttribute("headerRowCount", Form = XmlSchemaForm.Qualified)]
        public Nullable<uint> HeaderRowCount { get; set; }

        [Optional]
        [XmlAttribute("insertRow", Form = XmlSchemaForm.Qualified)]
        public Nullable<bool> InsertRow { get; set; }

        [Optional]
        [XmlAttribute("insertRowShift", Form = XmlSchemaForm.Qualified)]
        public Nullable<bool> InertRowShift { get; set; }

        [Optional]
        [XmlAttribute("totalsRowCount", Form = XmlSchemaForm.Qualified)]
        public Nullable<uint> TotalsRowCount { get; set; }

        [Optional]
        [XmlAttribute("totalsRowShown", Form = XmlSchemaForm.Qualified)]
        public Nullable<bool> TotalsRowShown { get; set; }

        [Optional]
        [XmlAttribute("published", Form = XmlSchemaForm.Qualified)]
        public Nullable<bool> Published { get; set; }

        [Optional]
        [XmlAttribute("headerRowDxfId", Form = XmlSchemaForm.Qualified)]
        public Nullable<uint> HeaderRowFormatId { get; set; }

        [Optional]
        [XmlAttribute("dataDxfId", Form = XmlSchemaForm.Qualified)]
        public Nullable<uint> DataAreaFormatId { get; set; }

        [Optional]
        [XmlAttribute("totalsRowDxfId", Form = XmlSchemaForm.Qualified)]
        public Nullable<uint> TotalsRowFormatId { get; set; }

        [Optional]
        [XmlAttribute("headerRowBorderDxfId", Form = XmlSchemaForm.Qualified)]
        public Nullable<uint> HeaderRowBorderFormatId { get; set; }

        [Optional]
        [XmlAttribute("tableBorderDxfId", Form = XmlSchemaForm.Qualified)]
        public Nullable<uint> TableBorderFormatId { get; set; }

        [Optional]
        [XmlAttribute("totalsRowBorderDxfId", Form = XmlSchemaForm.Qualified)]
        public Nullable<uint> TotalsRowBorderFormatId { get; set; }

        [Optional]
        [XmlAttribute("headerRowCellStyle", Form = XmlSchemaForm.Qualified)]
        public string HeaderRowCellStyle { get; set; }

        [Optional]
        [XmlAttribute("dataCellStyle", Form = XmlSchemaForm.Qualified)]
        public string DataStyleName { get; set; }

        [Optional]
        [XmlAttribute("totalsRowCellStyle", Form = XmlSchemaForm.Qualified)]
        public string TotalsRowStyle { get; set; }

        [Optional]
        [XmlAttribute("connectionId", Form = XmlSchemaForm.Qualified)]
        public Nullable<uint> ConnectionId { get; set; }

        #endregion

        #region Elements

        [Optional]
        [XmlElement("autoFilter", Namespace = Constants.ExcelMain)]
        public AutoFilter AutoFilter { get; set; }

        [Optional]
        [XmlElement("sortState", Namespace = Constants.ExcelMain)]
        public SortState SortState { get; set; }

        [Optional]
        [XmlElement("tableColumns", Namespace = Constants.ExcelMain)]
        public TableColumns TableColumns { get; set; }

        [Optional]
        [XmlElement("tableStyleInfo", Namespace = Constants.ExcelMain)]
        public TableStyleInfo TableStyleInfo { get; set; }

        [Optional]
        [XmlElement("extLst", Namespace = Constants.ExcelMain)]
        public ExtensionList ExtensionList { get; set; }

        #endregion

        public Table()
        {
        }

        public TableColumn AddColumn(string name)
        {
            if (TableColumns == null)
            {
                TableColumns = new TableColumns()
                {
                    Count = 0
                };
            }

            TableColumns.Count++;
            TableColumn col = new TableColumn()
            {
                Name = name,
                Id = (int)TableColumns.Count
            };
            TableColumns.Columns.Add(col);
            return col;
        }

        #region ISerializable members

        public byte[] Serialize()
        {
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("", Constants.ExcelMain);
            //ns.Add("xml", Constants.Xml);
            XmlSerializer serializer = new XmlSerializer(this.GetType());
            using (var stream = new IO.MemoryStream())
            {
                using (var writer = new IO.StreamWriter(stream, Encoding.UTF8))
                {
                    serializer.Serialize(writer, this, ns);
                    return stream.ToArray();
                }
            }
        }

        public void Deserialize(System.IO.Stream content)
        {
            XmlSerializer serializer = new XmlSerializer(this.GetType());
            Table t = serializer.Deserialize(content) as Table;

            this.AutoFilter = t.AutoFilter;
            this.Comment = t.Comment;
            this.ConnectionId = t.ConnectionId;
            this.DataAreaFormatId = t.DataAreaFormatId;
            this.DataStyleName = t.DataStyleName;
            this.DisplayName = t.DisplayName;
            this.ExtensionList = t.ExtensionList;
            this.HeaderRowBorderFormatId = t.HeaderRowBorderFormatId;
            this.HeaderRowCellStyle = t.HeaderRowCellStyle;
            this.HeaderRowCount = t.HeaderRowCount;
            this.HeaderRowFormatId = t.HeaderRowFormatId;
            this.Id = t.Id;
            this.InertRowShift = t.InertRowShift;
            this.InsertRow = t.InsertRow;
            this.Name = t.Name;
            this.Published = t.Published;
            this.Reference = t.Reference;
            this.RelationshipId = t.RelationshipId;
            this.SortState = t.SortState;
            this.TableBorderFormatId = t.TableBorderFormatId;
            this.TableColumns = t.TableColumns;
            this.TableStyleInfo = t.TableStyleInfo;
            this.TableType = t.TableType;
            this.TotalsRowBorderFormatId = t.TotalsRowBorderFormatId;
            this.TotalsRowCount = t.TotalsRowCount;
            this.TotalsRowFormatId = t.TotalsRowFormatId;
            this.TotalsRowShown = t.TotalsRowShown;
            this.TotalsRowStyle = t.TotalsRowStyle;
        }

        #endregion
    }
}
